package com.stenio.fancat.payment;

import com.alibaba.fastjson.JSON;
import com.stenio.fancat.util.DateUtil;
import com.stenio.fancat.util.StringUtil;
import com.stenio.fancat.util.XmlUtil;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.*;

/**
 * @author liuan
 * @create 2019-02-28 18:01
 */
@Component
public class PayMent {

    private static final Logger logger = LoggerFactory.getLogger(PayMent.class);

    @Value("${red.mch-id}")
    private String mch_id;

    @Value("${red.appid}")
    private String appid;

    @Value("${red.Addr}")
    private String Addr;

    @Value("${red.api_key}")
    private String api_key;

    /**
     * 发送微信红包
     * @param openId
     * @return
     */
    public String sendRedPacket(String openId,Integer redValue) {
        SortedMap<Object,Object> parameters = new TreeMap<>();
        String currTime = DateUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = StringUtil.buildRandom(4)+"";
        //随机字符串
        parameters.put("nonce_str", StringUtil.getNonceStr());
        //商户订单号
        parameters.put("mch_billno",strTime + strRandom);
        //商户号
        parameters.put("mch_id",mch_id);
        //公众号appid
        parameters.put("wxappid",appid);
        //商户名称
        parameters.put("send_name","图米云");
        //用户openid
        parameters.put("re_openid",openId);
        //付款金额
        parameters.put("total_amount",redValue);
        //红包发放总人数
        parameters.put("total_num",1);
        //红包祝福语
        parameters.put("wishing","红包祝福语");
        //ip地址
        parameters.put("client_ip",Addr);
        //活动名称
        parameters.put("act_name","活动名称");
        //备注
        parameters.put("remark","备注");
        //签名
        parameters.put("sign",createSign(parameters,api_key));
        String requestXml = XmlUtil.getRequestXml(parameters);
        CloseableHttpClient httpClient = null;
        Map<String,String> result = new HashMap<>();
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            String pathname = "/root/fancatV1.0/red_certificate/apiclient_cert.p12";
            FileInputStream inputStream = new FileInputStream(new File(pathname));
            try {
                keyStore.load(inputStream,mch_id.toCharArray());
            } finally {
                inputStream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (Exception e) {
            logger.info("读取证书信息错误：" + e.getMessage());
            e.printStackTrace();
        }
        try {
            String requestUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
            HttpPost httpPost = new HttpPost(requestUrl);
            StringEntity reqEntity  = new StringEntity(requestXml, "utf-8");
            reqEntity.setContentType("application/x-www-form-urlencoded");
            httpPost.setEntity(reqEntity);
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    // 从request中取得输入流
                    InputStream inputStream = entity.getContent();
                    // 读取输入流
                    SAXReader reader = new SAXReader();
                    Document document = reader.read(inputStream);
                    // 得到xml根元素
                    Element root = document.getRootElement();
                    // 得到根元素的所有子节点
                    List<Element> elementList = root.elements();
                    // 遍历所有子节点
                    for (Element e : elementList)
                    {
                        result.put(e.getName(), e.getText());
                    }
                    // 释放资源
                    inputStream.close();
                }
                EntityUtils.consume(entity);
            }finally {
                if(response != null) {
                    response.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("------------------发送红包结束---------------");
        logger.info("发送红包微信返回的信息是："+ JSON.toJSONString(result));
        //假如发送成功的话，保存发送的信息
        if(result.get("return_msg").equals("发放成功")) {
            logger.info("红包发放成功openid="+openId+",发送时间是："+DateUtil.getPreDay(new Date(),0));
            return "1";
        } else {
            logger.info("红包发放失败，openid="+openId+",发送时间是："+DateUtil.getPreDay(new Date(),0));
            return "2";
        }
    }

    /**
     * 企业付款到零钱
     * @param openId
     * @return
     */
    public Map<String, String> sendWallet(String openId,Integer redValue, String desc) {
        //创建一个唯一订单号
        String currTime = DateUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = StringUtil.buildRandom(4) + "";
        String orderId = strTime + strRandom;
        String xml = wxSendWallet(orderId, openId, String.valueOf(redValue), desc);
        Map<String,String> resultMap = new HashMap<>();
        try {
            //指定读取证书格式为PKCS12
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //linux系统,读取本机存放的PKCS12证书文件
            String pathname = "/root/fancatV1.0/red_certificate/apiclient_cert.p12";
            FileInputStream instream = new FileInputStream(new File(pathname));
            try {
                //指定PKCS12的密码(商户ID)
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            //指定TLS版本, Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            //设置httpclient的SSLSocketFactory
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
            //这里要设置编码，不然xml中有中文的话会提示签名失败或者展示乱码
            httppost.addHeader("Content-Type", "text/xml");
            StringEntity se = new StringEntity(xml, "UTF-8");
            httppost.setEntity(se);
            CloseableHttpResponse responseEntry = httpclient.execute(httppost);
            try {
                HttpEntity entity = responseEntry.getEntity();
                if (entity != null) {
                    System.out.println("响应内容长度 : " + entity.getContentLength());
                    SAXReader saxReader = new SAXReader();
                    Document document = saxReader.read(entity.getContent());
                    Element rootElt = document.getRootElement();
                    String resultCode = rootElt.elementText("result_code");
                    if (resultCode.equals("SUCCESS")) {
                        //保存红包信息到数据库
                        //保存用户领取记录
                        resultMap.put("partner_trade_no",rootElt.elementText("partner_trade_no"));
                        resultMap.put("payment_no",rootElt.elementText("payment_no"));
                        resultMap.put("payment_time",rootElt.elementText("payment_time"));
                    } else {
                        logger.info(rootElt.elementText("err_code_des"));
                    }
                }
                EntityUtils.consume(entity);
            } catch (Exception e) {
                logger.info("请求失败");
            } finally {
                responseEntry.close();
            }
        } catch (Exception e) {
            logger.info("请求失败");
        }
        return resultMap;
    }

    /**
     * 红包创建签名方法
     * @param parameters
     * @param api_key
     * @return
     */
    public String createSign(SortedMap<Object, Object> parameters,String api_key){
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Map.Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            /** 如果参数为key或者sign，则不参与加密签名 */
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        System.out.println("传过来的支付密钥api_key="+api_key);
        /** 支付密钥必须参与加密，放在字符串最后面 */
        sb.append("key=" + api_key);
        /** 记得最后一定要转换为大写 */
        String sign = StringUtil.md5(sb.toString()).toUpperCase();
        return sign;
    }


    /**
     * 零钱拼接xml
     * @param partner_trade_no
     * @param openid
     * @param total_amount
     * @return
     */
    public String wxSendWallet(String partner_trade_no, String openid,String total_amount,String desc) {
        String data = null;
        try {
            String nonceStr = StringUtil.getNonceStr();
            //SortedMap接口主要提供有序的Map实现，默认的排序是根据key值进行升序排序
            SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
            parameters.put("mch_appid", appid);
            parameters.put("mchid", mch_id);
            parameters.put("nonce_str", nonceStr);
            parameters.put("partner_trade_no", partner_trade_no);
            parameters.put("openid", openid);
            parameters.put("check_name", "NO_CHECK");
            parameters.put("amount", total_amount);
            parameters.put("spbill_create_ip", Addr);
            parameters.put("desc", desc);
            //签名
            parameters.put("sign", createSign2(parameters, api_key));
            data = XmlUtil.getRequestXml(parameters);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 零钱生成签名方法
     * @param packageParams
     * @param AppKey
     * @return
     */
    public static String createSign2(SortedMap<Object, Object> packageParams, String AppKey) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + AppKey);
        String sign = StringUtil.md5(sb.toString()).toUpperCase();
        return sign;
    }
}
